package org.appfuse.webapp.action;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.upload.FormFile;
import org.appfuse.Constants;
import org.appfuse.model.Criteria;
import org.appfuse.service.CriteriaExistsException;
import org.appfuse.service.CriteriaManager;
import org.appfuse.webapp.form.UploadForm;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

/**
 * This class handles the uploading of a resume (or any file) and writing it to
 * the filesystem. Eventually, it will also add support for persisting the files
 * information into the database.
 * 
 * <p>
 * <a href="UploadAction.java.html"><i>View Source</i></a>
 * </p>
 * 
 * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
 * 
 * @struts.action name="uploadForm" path="/uploadFile" scope="request"
 *                validate="true" input="failure"
 * @struts.action-set-property property="cancellable" value="true"
 * @struts.action-forward name="failure" path="/WEB-INF/pages/uploadForm.jsp"
 * @struts.action-forward name="success" path="/WEB-INF/pages/uploadDisplay.jsp"
 */
public class UploadAction extends BaseAction {

	public ActionForward upload(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// Did the user click the cancel button?
		if (isCancelled(request)) {
			request.removeAttribute(mapping.getAttribute());
			return (mapping.findForward("mainMenu"));
		}

		// this line is here for when the input page is upload-utf8.jsp,
		// it sets the correct character encoding for the response
		String encoding = request.getCharacterEncoding();

		if ((encoding != null) && (encoding.equalsIgnoreCase("utf-8"))) {
			response.setContentType("text/html; charset=gbk");
		}

		UploadForm theForm = (UploadForm) form;

		// retrieve the name
		String name = theForm.getName();

		// retrieve the file representation
		FormFile file = theForm.getFile();

		if (file == null) {
			return mapping.findForward("failure");
		}

		// retrieve the file name
		String fileName = file.getFileName();

		// retrieve the content type
		String contentType = file.getContentType();

		// retrieve the file size
		String size = (file.getFileSize() + " bytes");

		String data = null;
		String filePath = null;

		// the directory to upload to
		String uploadDir = servlet.getServletContext()
				.getRealPath("/resources")
				+ "/" + request.getRemoteUser() + "/";

		// write the file to the file specified
		File dirPath = new File(uploadDir);

		if (!dirPath.exists()) {
			dirPath.mkdirs();
		}

		// retrieve the file data
		InputStream stream = file.getInputStream();

		// write the file to the file specified
		OutputStream bos = new FileOutputStream(uploadDir + fileName);
		int bytesRead = 0;
		byte[] buffer = new byte[8192];

		while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
			bos.write(buffer, 0, bytesRead);
		}

		bos.close();

		filePath = dirPath.getAbsolutePath() + Constants.FILE_SEP
				+ file.getFileName();

		// close the stream
		stream.close();
		
		//read records from file and write to database.
		ActionMessages messages = readXml(filePath, request);
		if (!messages.isEmpty()){
			saveErrors(request.getSession(), messages);
			// destroy the temporary file created
			file.destroy();
			return mapping.findForward("failure");
		}else{
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("upload.succeeded"));
			saveMessages(request.getSession(), messages);
		}
		
		// place the data into the request for retrieval on next page
		request.setAttribute("friendlyName", name);
		request.setAttribute("fileName", fileName);
		request.setAttribute("contentType", contentType);
		request.setAttribute("size", size);
		request.setAttribute("data", data);
		request.setAttribute("filePath", filePath);

		String url = request.getContextPath() + "/resources" + "/"
				+ request.getRemoteUser() + "/" + file.getFileName();
		request.setAttribute("url", url);

		// destroy the temporary file created
		file.destroy();

		// return a forward to display.jsp
		// return mapping.findForward("success");
		return mapping.findForward("success");
	}

	public ActionForward cancel(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'cancel' method.");
		}
		return mapping.findForward("desktop");
	}

	protected boolean isTxt(String fileName) {
		if (StringUtils.isEmpty(fileName)) {
			return false;
		}
		return fileName.toLowerCase().endsWith("txt");
	}

	protected boolean isXml(String fileName) {
		if (StringUtils.isEmpty(fileName)) {
			return false;
		}
		return fileName.toLowerCase().endsWith("xml");
	}

	protected ActionMessages readXml(String fileName, HttpServletRequest request) {
		ActionMessages messages = new ActionMessages();
		if (StringUtils.isEmpty(fileName)) {
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"errors.upload.failed"));
			return messages;
		}

		File file = new File(fileName);
		if (!file.exists()) {
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"errors.upload.failed"));
			return messages;
		}
		
		SAXBuilder builder = new SAXBuilder();
		Document document = null;
		try {
			document = builder.build(file);
		} catch (JDOMException e) {
			e.printStackTrace();
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"errors.upload.formaterror"));
			return messages;
		} catch (IOException e) {
			e.printStackTrace();
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"errors.upload.formaterror"));
			return messages;
		}
		
		CriteriaManager mgr = (CriteriaManager) getBean("criteriaManager");
		if (document != null) {
			List list = document.getContent();
			Element root = document.getRootElement();
			List criterias = root.getChildren();

			for (Iterator it = criterias.iterator(); it.hasNext();) {
				Element e = (Element) it.next();
				Criteria c = new Criteria();
				List l = e.getChildren();
				{
					for (Iterator i = l.iterator(); i.hasNext();) {
						Element ee = (Element) i.next();
						String name = ee.getAttribute("name").getValue();
						if ("criterianumber".equalsIgnoreCase(name)) {
							c.setCriteriaNumber(ee.getTextTrim());
						} else if ("name".equalsIgnoreCase(name)) {
							c.setCriteriaName(ee.getTextTrim());
						} else if ("title".equalsIgnoreCase(name)) {
							c.setTitle(ee.getTextTrim());
						} else if ("parentnumber".equalsIgnoreCase(name)) {
							c.setParentNumber(ee.getTextTrim());
						} else if ("description".equalsIgnoreCase(name)) {
							c.setDescription(ee.getTextTrim());
						} else {
							messages.add(ActionMessages.GLOBAL_MESSAGE,
									new ActionMessage(
											"errors.upload.formaterror", e
													.getAttributeValue("id")));
						}
						//System.out.println(name);
						String value = ee.getAttribute("name").getValue();
					//	System.out.println(value);
						//System.out.println(ee.getTextTrim());
						try {
							mgr.saveCriteria(c);
						} catch (CriteriaExistsException e1) {
							log.warn(e1.getMessage());
							messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
									"errors.existing.criteria", c.getCriteriaNumber()));
						}
						
					}
				}
			}

		}
		return messages;
	}

	/**
	 * Iterate through all the items in this structured DMOZ file. Add each URL
	 * to the web db.
	 */
	/*
	 * public void injectDmozFile(File dmozFile, int subsetDenom, boolean
	 * includeAdult, boolean includeDmozDesc, int skew, Pattern topicPattern)
	 * throws IOException, SAXException, ParserConfigurationException {
	 * nextFetch = dmozFile.lastModified();
	 * 
	 * SAXParserFactory parserFactory = SAXParserFactory.newInstance();
	 * SAXParser parser = parserFactory.newSAXParser(); XMLReader reader =
	 * parser.getXMLReader();
	 *  // Create our own processor to receive SAX events RDFProcessor rp = new
	 * RDFProcessor(reader, subsetDenom, includeAdult, includeDmozDesc, skew,
	 * topicPattern); reader.setContentHandler(rp); reader.setErrorHandler(rp);
	 * LOG.info("skew = " + rp.hashSkew);
	 *  // // Open filtered text stream. The UTF8Filter makes sure that // only
	 * appropriate XML-approved UTF8 characters are received. // Any
	 * non-conforming characters are silently skipped. // XMLCharFilter in = new
	 * XMLCharFilter(new BufferedReader( new InputStreamReader(new
	 * BufferedInputStream( new FileInputStream(dmozFile)), "UTF-8"))); try {
	 * InputSource is = new InputSource(in); reader.parse(is); } catch
	 * (Exception e) { LOG.severe(e.toString()); e.printStackTrace(System.out);
	 * System.exit(0); } finally { in.close(); } }
	 */
}
